package core

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/qiniu/api.v7/auth/qbox"
	"github.com/qiniu/api.v7/kodo"
	"golang.org/x/net/context"
)

// 全局七牛client链接
var qiniu_client *kodo.Client

// 默认七牛存储空间
var qiniu_bucket kodo.Bucket

// ACCESS_KEY, SECRET_KEY
var (
	qiniu_ak         string = "usul9wzuSgV14jLeR6QT8Ttnt-iafXW8m5NnrwUN"
	qiniu_sk         string = "juiZyWKVwfHqjuGZ2DrGhZ0I1pBU5Eeg10o41HoI"
	qiniu_bucketname string = "htmlcopy"
	qn_domain        string = "http://o9iuwbkt7.bkt.clouddn.com/"
	qiniu_filek      string = "pfop.txt"          // 该文件默认值，必须在空间中存在，接口规范（并无实质作用）
	qiniu_pipeline   string = "htmlcopy-pipeline" // 执行作业队列
)

func init() {
	kodo.SetMac(qiniu_ak, qiniu_sk)
	qiniu_client = kodo.New(0, nil)
	qiniu_bucket = qiniu_client.Bucket(qiniu_bucketname)
}

// 实现Saveer, RespDoc接口
type QiNiu struct {
}

func NewQiniu() *QiNiu {
	return &QiNiu{}
}

// 实现Saveer接口
// 本方法实现将body存储到七牛云中
func (c *QiNiu) SaveFile(url, key string, body []byte) error {

	ctx := context.Background()
	err := qiniu_bucket.Put(ctx, nil, key, bytes.NewReader(body), int64(len(body)), nil)
	if err != nil {
		return err
	}

	return nil
}

// 实现Saveer接口
func (c *QiNiu) SaveRoot() string {
	return qn_domain
}

// 实现RespDoc接口
func (c *QiNiu) GetResponse(url string, client *http.Client) (*http.Response, error) {
	return client.Get(url)
}

// 实现Logger接口
func (c *QiNiu) Write(b []byte) (int, error) {
	fmt.Println(string(b))
	return len(b), nil
}

// 实现Ziper接口
func (c *QiNiu) Zip(mks []string) (pid, key string, err error) {
	return MkZip(mks)
}

// 将mks中的key资源文件进行压缩处理， 并保存到qiniu_bucket的空间中
// mks中至少又一个资源地址
// 返回该次任务的qiniu persistentId， 和文件的key
func MkZip(mks []string) (pid, key string, err error) {
	if len(mks) == 0 {
		err = errors.New("mks must have one value")
		return
	}
	mac := qbox.NewMac(qiniu_ak, qiniu_sk)

	// 创建请求body前固定部分
	param := "bucket=" + qiniu_bucketname + "&key=" + qiniu_filek + "&force=1&pipeline=" + qiniu_pipeline
	// 追加mkzip请求参数
	bf := bytes.NewBuffer([]byte(param + "&fops=mkzip/2"))
	for _, v := range mks {
		i := Base64EncodedURL(qn_domain + v) // 将资源地址进行Base64编码,需要添加domain来确认实际访问地址
		_, err = bf.WriteString("/url/" + i) // 将资源添加到地址中
		if err != nil {
			return
		}
	}
	// 追加saveas请求参数
	key = "zip/" + upkey(".zip")
	bf.WriteString("|saveas/" + Base64EncodedURL(qiniu_bucketname+":"+key))

	// 创建请求
	client := &http.Client{}
	req, err := http.NewRequest("POST", "http://api.qiniu.com/pfop", bf)
	if err != nil {
		return
	}
	accessToken, _ := mac.SignRequest(req, true) // 创建AccessToken
	req.Header.Add("Host", "api.qiniu.com")
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Authorization", "QBox "+accessToken)

	resp, err := client.Do(req)
	if err != nil {
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	// 解析响应结果
	if resp.StatusCode != 200 {
		fmt.Printf("%v, %v", resp.StatusCode, string(body))
		err = errors.New(fmt.Sprintf("response statuscode is %v", resp.StatusCode))
		return
	}
	result := make(map[string]string)
	json.Unmarshal(body, &result)
	pid = result["persistentId"]
	return
}

func Base64EncodedURL(url string) string {
	return base64.URLEncoding.EncodeToString([]byte(url))
}
